package cn.john.hrm.webconfig;

import cn.john.hrm.handler.MyAuthenFailureHandler;
import cn.john.hrm.handler.MyAuthenSuccessHandler;
import cn.john.hrm.handler.MyAuthorDeniedHandler;
import cn.john.hrm.mapper.PermissionMapper;
import cn.john.hrm.service.MySecurityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

// 交给spring容器管理
@Configuration
// 开启web安全配置
@EnableWebSecurity
// 允许pre和post方式的方法注解授权
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MySecurityService mySecurityService;
    @Autowired
    private DataSource dataSource;

    // 配置记住我功能 token存储位置
    @Bean
    public PersistentTokenRepository getTokenRepository() {
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();
        // 配置数据库连接池
        repository.setDataSource(dataSource);
        // 可以使用方法在第一次访问的时候自动创建表
        //repository.setCreateTableOnStartup(true);
        return repository;
    }

    // 指定密码加密器
    @Bean
    public PasswordEncoder getPwdEncoder() {
        // 无加密，明文密码
        //return NoOpPasswordEncoder.getInstance();
        // 加密
        return new BCryptPasswordEncoder();
    }

    // 用户的信息 交给springsecurity管理
    /*@Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager detailsManager = new InMemoryUserDetailsManager();
        // 在内存中创建用户 真实情况应该是从数据库中查询
        User user = new User("john", "123", new ArrayList<>());
        detailsManager.createUser(user);
        return detailsManager;
    }*/

    /*@Override
    protected void configure(HttpSecurity http) throws Exception {
        // 查出系统所有的权限
        List<Permission> allPermissions = permissionMapper.getAllPermission();

        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = http.authorizeRequests();// 授权配置
                // 添加权限
                allPermissions.stream().forEach(permission -> {
                    // 访问哪个接口 需要对应哪些权限 交给security管理
                    registry.antMatchers(permission.getResource()).hasAuthority(permission.getSn());
                });

                registry.antMatchers("/login").permitAll()      // 登录路径放行
                .antMatchers("/login.html").permitAll() // 自定义登录页面放行
                .anyRequest().authenticated()                       // 其他路径都要认证之后才允许访问
                .and().formLogin()                                  // 允许表单登录
                //.successForwardUrl("/success")                      // 设置登录成功页
                .successHandler(new MyAuthenSuccessHandler())       // 设置认证成功后的处理
                .failureHandler(new MyAuthenFailureHandler())       // 设置认证失败后的处理
                .loginPage("/login.html")                           // 自定义登录页面
                .loginProcessingUrl("/login")                       // 自定义登录处理地址
                .and().logout().permitAll()                         // 退出登录路径放行
                .and().csrf().disable();                            // 关闭跨站伪造检查
    }*/

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().accessDeniedHandler(new MyAuthorDeniedHandler())
                .and().authorizeRequests()                                    // 授权配置
                .antMatchers("/login").permitAll()      // 登录路径放行
                .antMatchers("/login.html").permitAll() // 自定义登录页面放行
                .anyRequest().authenticated()                       // 其他路径都要认证之后才允许访问
                .and().formLogin()                                  // 允许表单登录
                //.successForwardUrl("/success")                      // 设置登录成功页
                .successHandler(new MyAuthenSuccessHandler())       // 设置认证成功后的处理
                .failureHandler(new MyAuthenFailureHandler())       // 设置认证失败后的处理
                .loginPage("/login.html")                           // 自定义登录页面
                .loginProcessingUrl("/login")                       // 自定义登录处理地址
                .and().logout().permitAll()                         // 退出登录路径放行
                .and().csrf().disable();                            // 关闭跨站伪造检查
        // 记住我配置
        http.rememberMe()
                .tokenRepository(getTokenRepository())              // 指定token存储方案
                .tokenValiditySeconds(3600)                         // 设置过期时间
                .userDetailsService(mySecurityService);
    }
}
